#!/usr/bin/perl
#
# CPUflags provides database for cpuflags (with and without 
# optimisation) for different operating systems and processors. 
# By autodetecting the current CPU, optimal cflags for the 
# target system are returned.
# 
#   supported platforms : Linux, Solaris, AIX, IRIX, Darwin
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation (version 2 of the License).
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

###############################################################
###############################################################
##
## default settings
##
###############################################################
###############################################################

$system      = "";
$cpu         = $ENV{"CPU"};
$bits        = 64;
$show_cpu    = "0";
$show_cflags = "1";
$show_opt    = "0";
$compiler    = "cc";
$compversion = "";
$compsubver  = 0;
$version     = "0.6.1";
$verbosity   = 0;

$cflags      = "";
$oflags      = "-O";


###############################################################
###############################################################
##
## misc. functions
##
###############################################################
###############################################################

###############################################################
#
# print error message
# 
sub error 
{
    print( stderr $_[0] );
}

###############################################################
#
# show usage
#

sub show_usage
{
    print "cpuflags v$version by Ronald Kriemann\n";
    print "usage: cpuflags [ options ] \n";
    print "  where options include :\n";
    print "    --cpu <name>        : show flags for given cpu-identifier (default autodetect)\n";
    print "    --comp <name>       : set compiler to use (default: cc)\n";
    print "    --compver <name>    : set exact compiler version (e.g. gcc-3.3.1, see below)\n";
    print "    --showcpu           : print CPU identifier (default off)\n";
    print "    --[no]cflags        : (don't) print compiler flags (default on)\n";
    print "    --[no]opt           : (don't) print optimisation flags (default off)\n";
    print "    -32|-64             : set bitsize (default: max. available)\n";
    print "    -h, --help          : print this message\n";
    print "    -v, --verbose [int] : verbosity level (default 0)\n";
    print "    -V, --version       : print version number\n";
    print "\n";
    print "  Supported systems and compilers:\n";
    print "    Linux   : gcc-2.x, gcc-3.x, icc-[5678], pgi\n";
    print "    Solaris : gcc-2.x, gcc-3.x, suncc-[67], kcc\n";
    print "    AIX     : gcc, xlC\n";
    print "    IRIX    : gcc, mipscc\n";
    print "    Darwin  : gcc\n";
    print "\n";
    print "  Supported CPUs:\n";
    print "    Linux   : i386, i486, i586, pentium, pentium-mmx, pentium-pro,\n";
    print "              p2, p3, p3-sse, p3-centrino, p3-xeon, p4, p4-xeon,\n";
    print "              k6, k6-2, k6-3, athlon, duron, athlon-tbird, athlon-xp,\n";
    print "              duron-xp, opteron, via-c3a, ppc750, ppc7450\n";
    print "    Solaris : ultra1, ultra2, ultra3, ultra3cu\n";
    print "    AIX     : power4\n";
    print "    IRIX    : mips4\n";
    print "    Darwin  : ppc7450\n";
    print "\n";
}

###############################################################
#
# parse command-line
#

sub parse_cmdline
{
    for ( $i = 0; $i <= $#ARGV; $i++ )
    {
	$arg = $ARGV[$i];

      switch: for ( $arg )
      {
	  if ( /^--cpu/ )      
	  {
	      $i++;
	      if ( $i <= $#ARGV and not $ARGV[$i] =~ /^-/ )
	      {
		  $cpu = $ARGV[$i];
		  last switch;
	      }
	      else
	      {
		  error( "error: expected name after --cpu\n" );
		  exit( 1 );
	      }
	  }
	  elsif ( /^--showcpu/ )  { $show_cpu    = 1; last switch; }
	  elsif ( /^--cflags/ )   { $show_cflags = 1; last switch; }
	  elsif ( /^--nocflags/ ) { $show_cflags = 0; last switch; }
	  elsif ( /^--opt/ )      { $show_oflags = 1; last switch; }
	  elsif ( /^--noopt/ )    { $show_oflags = 0; last switch; }
	  elsif ( /^--compver/ )
	  {
	      $i++;
	      if ( $i <= $#ARGV and not $ARGV[$i] =~ /^-/ )
	      {
		  $compversion = $ARGV[$i];
		  $compsubver  = $compversion;
		  $compsubver  =~ s/.*\.//g;
		  last switch;
	      }
	      else
	      {
		  error( "error: expected name after --compver\n" );
		  exit( 1 );
	      }
	  }
	  elsif ( /^--comp/ )
	  {
	      $i++;
	      if ( $i <= $#ARGV and not $ARGV[$i] =~ /^-/ )
	      {
		  $compiler = $ARGV[$i];
		  last switch;
	      }
	      else
	      {
		  error( "error: expected name after --comp\n" );
		  exit( 1 );
	      }
	  }
	  elsif ( /^(-h|--help)/ )
	  {
	      show_usage();
	      exit( 0 );
	  }
	  elsif ( /^(-V|--version)/ )
	  {
	      print "cpuflags v$version by Ronald Kriemann\n";
	      exit( 0 );
	  }
	  elsif ( /^(-v|--verbose)/ )
	  {
	      if ( $i+1 <= $#ARGV and not $ARGV[$i+1] =~ /^-/ )
	      {
		  $i++;
		  $verbosity = $ARGV[$i];
		  last switch;
	      }
	      else
	      {
		  $verbosity = 1;
		  last switch;
	      }
	  }
	  elsif ( /^-32/ )  { $bits = 32; last switch; }
	  elsif ( /^-64/ )  { $bits = 64; last switch; }
      }
    }
}

###############################################################
###############################################################
##
## setup compiler-flags
##
###############################################################
###############################################################

###############################################################
#
# setup basic CFLAGS
# 
sub set_cflags 
{
    if ( $system =~ /Linux|CYGWIN/ )
    {
	if ( $compversion =~ /gcc-2/ )
	{ 
	    for ( $cpu )
	    {
		if    ( /i386/ )  
		{ $cflags = "-march=i386"; }
		elsif ( /i486/ )               
		{ $cflags = "-march=i386"; }
		elsif ( /i586|pentium($|-mmx)|via-c3/ ) 
		{ $cflags = "-march=i586"; }
		elsif ( /k6/ ) 
		{ $cflags = "-march=k6"; }
		elsif ( /pentiumpro|p2|p3|p4|athlon|duron|opteron/ ) 
		{ $cflags = "-march=i686"; }
		elsif ( /ppc750/ )              
		{ $cflags = "-mcpu=750 -mpowerpc-gfxopt  -fsigned-char"; }
		elsif ( /ppc74[05]0/ )
		{ 
		    if ( /ppc7400/ ) { $cflags = "-mcpu=7400" }
		    else             { $cflags = "-mcpu=7450" }
		    
		    $cflags = "$cflags -mpowerpc-gfxopt -fsigned-char"; 
		}
		else
		{
		    error( "unsupported CPU in this compiler\n" );
		}
	    }
	}
	elsif ( $compversion =~ /gcc-3/ )
	{
	    for ( $cpu )
	    {
		if    ( /i386/ )          { $cflags = "-march=i386"; }
		elsif ( /i486/ )          { $cflags = "-march=i386"; }
		elsif ( /i586|pentium/ )  { $cflags = "-march=i586"; }
		elsif ( /k6$/ )           { $cflags = "-march=k6"; }
		elsif ( /k6-2/ )          { $cflags = "-march=k6-2"; }
		elsif ( /k6-3/ )          { $cflags = "-march=k6-3"; }
		elsif ( /pentium-mmx/ )   { $cflags = "-march=pentium-mmx"; }
		elsif ( /pentiumpro/ )    { $cflags = "-march=i686"; }
		elsif ( /p2/ )            { $cflags = "-march=pentium2"; }
		elsif ( /p3/ ) 
		{ 
		    $cflags = "-march=pentium3"; 

		    if    ( /sse|xeon/ )  { $cflags = "$cflags -mfpmath=sse";  }
		    elsif ( /centrino/ )
		    {
			if ( $compsubver >= 4 ) { $cflags = "$cflags -msse2 -mfpmath=sse2"; }
			else                    { $cflags = "$cflags -mfpmath=sse"; }
		    }
		    else
		    { $cflags = "$cflags"; }
		}
		elsif ( /p4/ )  
		{ 
		    if ( $compsubver >= 4 ) { $cflags = "-march=pentium4 -mfpmath=sse2"; }
		    else                    { $cflags = "-march=pentium4 -mfpmath=sse"; }
		}
		elsif ( /athlon|duron/ ) 
		{ 
		    if    ( /-tbird/ )
		    { $cflags = "-march=athlon-tbird"; }
		    elsif ( /-xp/ )    
		    { $cflags = "-march=athlon-xp -msse -mfpmath=sse,387"; }
		    else 
		    { $cflags = "-march=athlon"; }
		}
		elsif ( /opteron/ )  { $cflags = "-march=k8 -mfpmath=sse,387"; }
		elsif ( /via-c3a/ )  { $cflags = "-march=c3 -msse -mfpmath=sse"; }
		elsif ( /ppc750/ )   { $cflags = "-mcpu=750 -mpowerpc-gfxopt -fsigned-char"; }
		elsif ( /ppc74[05]0/ )
		{ 
		    if ( /ppc7400/ ) { $cflags = "-mcpu=7400" }
		    else             { $cflags = "-mcpu=7450" }
		    
		    $cflags = "$cflags -mpowerpc-gfxopt -maltivec -mabi=altivec -fsigned-char"; 
		}
		else
		{
		    error( "unsupported CPU in this compiler\n" );

		    # setup some flags based on cpuinfo
		    $cflags = ""; 

		    $cflags = "$cflags -mmmx"   if ( $proc_flags{"mmx"} );
		    $cflags = "$cflags -msse"   if ( $proc_flags{"sse"} );
		    $cflags = "$cflags -msse2"  if ( $proc_flags{"sse2"} );
		    $cflags = "$cflags -m3dnow" if ( $proc_flags{"3dnow"} );
		}
	    }
	}
	elsif ( $compversion =~ /icc/ )
	{
	    for ( $cpu )
	    {
		if    ( /pentium$/ )       { $cflags = "-tpp5"; }
		elsif ( /pentium-mmx/ )    { $cflags = "-tpp5 -xM"; }
		elsif ( /k6/ )             { $cflags = "-tpp5 -xM"; }
		elsif ( /pentiumpro/ )     { $cflags = "-tpp6"; }
		elsif ( /p2/ )             { $cflags = "-tpp6 -xM"; }
		elsif ( /p3/ ) 
		{ 
		    $cflags = "-tpp6"; 

		    if    ( /sse|xeon/ ) { $cflags = "$cflags -march=pentiumiii -xK";  }
		    elsif ( /centrino/ ) { $cflags = "$cflags -xB"; }
		    else                 { $cflags = "$cflags -march=pentiumii -xM"; }
		}
		elsif ( /p4/ )             { $cflags = "-tpp7 -xW"; }
		elsif ( /athlon|duron/ ) 
		{ 
		    if ( /-xp/ ) { $cflags = "-tpp6 -xK"; }
		    else         { $cflags = "-tpp6 -xM"; }
		}
		elsif ( /opteron/ )  { $cflags = "-tpp7 -xW"; }
		elsif ( /via-c3a/ )  { $cflags = "-tpp5 -xK"; }
		else
		{
		    error( "unsupported CPU in this compiler\n" );
		}
	    }
	}
	elsif ( $compversion =~ /pgi/ )
	{
	    for ( $cpu )
	    {
		if    ( /i386|i486|i586/ )   { $cflags = "-tp px"; }
		elsif ( /pentium($|-mmx)/ )  { $cflags = "-tp p5"; }
		elsif ( /pentiumpro|p2|p3/ ) { $cflags = "-tp p6"; }
		elsif ( /p4/ )               { $cflags = "-tp p7"; }
		elsif ( /athlon|duron/ )     { $cflags = "-tp p6"; }
		elsif ( /opteron/ )          
		{ 
		    if ( $bits == 32 ) { $cflags = "-tp k8-32"; }
		    else               { $cflags = "-tp k8-64"; }
		}
		elsif ( /via-c3a/ )  { $cflags = "-tp p5"; }
		else
		{
		    error( "unsupported CPU in this compiler\n" );
		}
	    }
	}
	else 
	{
	    error( "cpuflags: unsupported compiler ($compversion)\n" );
	    exit(1);
	}
    }
    elsif ( $system eq "Solaris" )
    {
	if ( $compversion =~ /gcc-2/ )
	{
	    if ( $cpu =~ /ultra[123]/ ) { $cflags = "-mcpu=ultrasparc"; }
	}
	elsif ( $compversion =~ /gcc-3/ )
	{
	    if ( $bits == 32 ) { $opt = ""; }
	    else               { $opt = "-m64"; }

	    if    ( $cpu =~ /ultra[12]/ ) { $cflags = "-mcpu=ultrasparc $opt"; }
	    elsif ( $cpu =~ /ultra3/    ) { $cflags = "-mcpu=ultrasparc3  $opt"; }
	}
	elsif ( $compversion =~ /suncc|kcc/ )
	{
	    for ( $cpu )
	    {
		if    ( /ultra1/ ) 
		{
		    if ( $bits == 32 ) { $cflags = "-xtarget=ultra -xarch=v8"; }
		    else               { $cflags = "-xtarget=ultra -xarch=v9"; }
		}
		elsif ( /ultra2/ ) 
		{
		    if ( $bits == 32 ) { $cflags = "-xtarget=ultra2 -xarch=v8plusa"; }
		    else               { $cflags = "-xtarget=ultra2 -xarch=v9a"; }
		}
		elsif ( /ultra3/ ) 
		{
		    if ( $compversion =~ /suncc-6/ ) { $cflags = "-xtarget=ultra3"; }
		    else                             { $cflags = "-xtarget=ultra3cu"; }

		    if ( $bits == 32 ) { $cflags = "$cflags -xarch=v8plusb"; }
		    else               { $cflags = "$cflags -xarch=v9b"; }
		}
	    }
	}
	else 
	{
	    error( "cpuflags: unsupported compiler ($compversion)\n" );
	    exit(1);
	}
    }
    elsif ( $system eq "AIX" )
    {
	if    ( $compversion =~ /gcc-[23]/ )
	{ 
	    if ( $bits == 32 ) { $cflags = "-mcpu=power2"; }
	    else               { $cflags = "-mcpu=powerpc64 -maix64"; }
	}
	elsif ( $compversion =~ /xlC/ )
	{
	    if ( $bits == 32 ) { $cflags = "-qarch=pwr4 -qtune=pwr4"; }
	    else               { $cflags = "-q64 -qarch=pwr4 -qtune=pwr4"; }
	}
	else
	{
	    error( "cpuflags: unsupported compiler ($compversion)\n" );
	    exit(1);
	}
    }
    elsif ( $system eq "IRIX" )
    {
	if    ( $compversion =~ /gcc-2/ )  { $cpuflags{"r10000"} = "-march=mips4"; }
	elsif ( $compversion =~ /gcc-3/ )
	{
	    if ( $bits == 32 ) { $cflags = "-march=mips4"; }
	    else               { $cflags = "-march=mips4 -mabi=64"; }
	}
	elsif ( $compversion =~ /mipscc/ ) 
	{
	    if ( $bits == 32 ) { $cflags = "-mips4"; }
	    else               { $cflags = "-mips4 -64"; }
	}
	else 
	{
	    error( "cpuflags: unsupported compiler ($compversion)\n" );
	    exit(1);
	}
    }
    elsif ( $system eq "Darwin" )
    {
	if ( $compversion =~ /gcc/ )
	{ 
	    for ( $cpu )
	    {
		if    ( /ppc750/ )   { $cflags = "-mcpu=750 -mpowerpc-gfxopt -fsigned-char"; }
		elsif ( /ppc74[05]0/ )
		{ 
		    if ( /ppc7400/ ) { $cflags = "-mcpu=7400" }
		    else             { $cflags = "-mcpu=7450" }
		    
		    $cflags = "$cflags -mpowerpc-gfxopt -maltivec -mabi=altivec -fsigned-char"; 
		}
		else
		{
		    error( "unsupported CPU in this compiler\n" );
		}
	    }
	}
    }
}

###############################################################
#
# setup optimisation CFLAGS
# 
sub set_oflags 
{
    if ( $system =~ /Linux|CYGWIN/ )
    {
	if ( $compversion =~ /gcc-[23]/ )
	{ 
	    $oflags = "-O3 -fomit-frame-pointer -finline-functions";
	    $oflags = "$oflags -ffast-math -funroll-loops -fexpensive-optimizations";
	    
	    if ( $cpu =~ /i586|k6|pentium|p[234]|athlon|duron|via-c3/ )
	    { $oflags = "$oflags -fschedule-insns2 -malign-double"; }

	    if ( $cpu =~ /p3|athlon|duron/ )
	    { $oflags = "$oflags -fprefetch-loop-arrays"; }

	    if ( $cpu =~ /opteron/ )
	    { $oflags = "$oflags -fschedule-insns2"; }
	}
	elsif ( $compversion =~ /icc/ )
	{
	    $oflags = "-O3 -Ob2 -unroll -ip";
	}
	elsif ( $compversion =~ /pgi/ )
	{
	    $oflags = "-O3 -fast -Minline";
	    
	    if ( $cpu =~ /p[234]|athlon|duron|opteron|via-c3/ )
	    { $oflags = "$oflags -Mvect"; }
	}
	else 
	{
	    error( "cpuflags: unsupported compiler ($compversion)\n" );
	    exit(1);
	}
    }
    elsif ( $system eq "Solaris" )
    {
	if ( $compversion =~ /gcc-[23]/ )
	{
	    $oflags = "-O3 -fomit-frame-pointer -finline-functions";
	    $oflags = "$oflags -ffast-math -funroll-loops -fexpensive-optimizations";
	}
	elsif ( $compversion =~ /suncc/ )
	{
	    $oflags = "-fast -xO5";

	    if ( $cpu =~ /ultra3/ ) 
	    {
		$oflags = "$oflags -xprefetch"; 

		if ( $compversion =~ /suncc-7/ )
		{ $oflags = "$oflags -xprefetch_level=3"; }
	    }
	}
	elsif ( $compversion =~ /kcc/ )
	{
	    $oflags = "-fast +K3 -xO5 --abstract_float";

	    if ( $cpu =~ /ultra3/ ) { $oflags = "$oflags -xprefetch"; }
	}
	else 
	{
	    error( "cpuflags: unsupported compiler ($compversion)\n" );
	    exit(1);
	}
    }
    elsif ( $system eq "AIX" )
    {
	if ( $compversion =~ /gcc-[23]/ )
	{
	    $oflags = "-O3 -fomit-frame-pointer -finline-functions -ffast-math -funroll-loops";
	}
	elsif ( $compversion =~ /xlC/ )
	{
	    $oflags = "-O2 -qinline -qrtti";
	}
	else 
	{
	    error( "cpuflags: unsupported compiler ($compversion)\n" );
	    exit(1);
	}
    }
    elsif ( $system eq "IRIX" )
    {
	if ( $compversion =~ /gcc-[23]/ )
	{
	    $oflags = "-O3 -fomit-frame-pointer -finline-functions -ffast-math -funroll-loops";
	}
	elsif ( $compversion =~ /mipscc/ )
	{
	    $oflags = "-O3";
	}
	else 
	{
	    error( "cpuflags: unsupported compiler ($compiler)\n" );
	    exit(1);
	}
    }
}

###############################################################
###############################################################
##
## determine processor
##
###############################################################
###############################################################

###############################################################
#
# functions for Linux
#

sub parse_linux
{
    @cpuinfo = `cat /proc/cpuinfo 2>&1`;

    $vendor  = "";
    $cputype = "";

    foreach $line (@cpuinfo)
    {
	$entry = $line;
	$entry =~ s/[ \t]*\:.*//g;
	$entry =~ s/\n//g;

	$data  = $line;
	$data  =~ s/.*\: *//g;
	$data  =~ s/\n//g;

	print "entry = ($entry), data = ($data)\n" if ( $verbosity >= 2 );

	if    ( $entry eq "vendor_id"  ) { $vendor    = $data; }
	elsif ( $entry eq "cpu"        ) { $cputype   = $data; }
	elsif ( $entry eq "cpu family" ) { $family    = $data; }
	elsif ( $entry eq "model"      ) { $model     = $data; }
	elsif ( $entry eq "flags"      ) 
	{
	    #
	    # parse processor flags
	    #

	    for ( $data )
	    {
		if ( /mmx/ )   { $proc_flags{"mmx"}   = 1; }
		if ( /sse/ )   { $proc_flags{"sse"}   = 1; }
		if ( /sse2/ )  { $proc_flags{"sse2"}  = 1; }
		if ( /3dnow/ ) { $proc_flags{"3dnow"} = 1; }
	    }
	}
    }

    if ( $verbosity >= 1 )
    {
	print "Vendor  = $vendor\n";
	print "CPUtype = $cputype\n";
	print "Family  = $family\n";
	print "Model   = $model\n";
	print "has MMX\n"   if ( $proc_flags{"mmx"} ); 
	print "has SSE\n"   if ( $proc_flags{"sse"} ); 
	print "has SSE2\n"  if ( $proc_flags{"sse2"} ); 
	print "has 3DNOW\n" if ( $proc_flags{"3dnow"} ); 
    }

    #
    # switch between different outputs
    #

    if ( $vendor ne "" )
    {
	if ( $vendor eq "AuthenticAMD" )
	{
	    if ( $family eq "4" ) 
	    {
		# AMD 486
		$cpu = "i486";
	    }
	    elsif ( $family eq "5" ) 
	    {
		# K5 and K6
		if    ( $model eq "0" ) { $cpu = "i586"; }
		elsif ( $model eq "1" ) { $cpu = "i586"; }
		elsif ( $model eq "2" ) { $cpu = "i586"; }
		elsif ( $model eq "3" ) { $cpu = "i586"; }
		elsif ( $model eq "6" ) { $cpu = "k6"; }
		elsif ( $model eq "7" ) { $cpu = "k6"; }
		elsif ( $model eq "8" ) { $cpu = "k6-2"; }
		elsif ( $model eq "9" ) { $cpu = "k6-3"; }
		elsif ( $model eq "13" ) { $cpu = "k6-3"; }
		else  { error( "cpuflags : unsupported processor type\n" ); 
                        $cpu = "k5"; }
	    }
	    elsif ( $family eq "6" ) 
	    {
		# Athlon
		if    ( $model eq "1"  ) { $cpu = "athlon"; }
		elsif ( $model eq "2"  ) { $cpu = "athlon"; }
		elsif ( $model eq "3"  ) { $cpu = "duron"; }
		elsif ( $model eq "4"  ) { $cpu = "athlon-tbird"; }
		elsif ( $model eq "6"  ) { $cpu = "athlon-xp"; }
		elsif ( $model eq "7"  ) { $cpu = "duron-xp"; }
		elsif ( $model eq "10" ) { $cpu = "athlon-xp"; }
		else  { error( "cpuflags : unknown Athlon model\n" ); 
                        $cpu = "athlon-tbird"; }
	    }
	    elsif ( $family eq "15" ) 
	    {
		# AMD Opteron
		if    ( $model eq "5" ) { $cpu = "opteron"; }
		else  { error( "cpuflags : unknown Opteron model\n" ); 
                        $cpu = "opteron"; }
	    }
	}
	elsif ( $vendor eq "GenuineIntel" )
	{
	    if    ( $family eq "3" )  { $cpu = "i386"; }
	    elsif ( $family eq "4" )  { $cpu = "i486"; }
	    elsif ( $family eq "5" ) 
	    {
		# Pentium
		if    ( $model eq "0" ) { $cpu = "pentium"; }
		elsif ( $model eq "1" ) { $cpu = "pentium"; }
		elsif ( $model eq "2" ) { $cpu = "pentium"; }
		elsif ( $model eq "3" ) { $cpu = "pentium"; }
		elsif ( $model eq "4" ) { $cpu = "pentium-mmx"; }
		elsif ( $model eq "7" ) { $cpu = "pentium"; }
		elsif ( $model eq "8" ) { $cpu = "pentium-mmx"; }
		else  { error( "cpuflags : unknown Pentium model\n" ); 
                        $cpu = "pentium"; }
	    }
	    elsif ( $family eq "6" ) 
	    {
		# PentiumPro, P2, P3
		if    ( $model eq "0"  ) { $cpu = "pentiumpro"; }
		elsif ( $model eq "1"  ) { $cpu = "pentiumpro"; }
		elsif ( $model eq "3"  ) { $cpu = "p2"; }
		elsif ( $model eq "5"  ) { $cpu = "p2"; }
		elsif ( $model eq "6"  ) { $cpu = "p2"; }
		elsif ( $model eq "7"  ) { $cpu = "p3"; }
		elsif ( $model eq "8"  ) { $cpu = "p3-sse"; }
		elsif ( $model eq "9"  ) { $cpu = "p3-centrino"; }
		elsif ( $model eq "10" ) { $cpu = "p3-xeon"; }
		elsif ( $model eq "11" ) { $cpu = "p3-sse"; }
		else  { error( "cpuflags : unknown Pentium3 model\n" );
			$cpu = "pentiumpro"; }
	    }
	    elsif ( $family eq "15" ) 
	    {
		# Pentium 4
		if    ( $model eq "2"  ) { $cpu = "p4-xeon"; }
		else  { error( "cpuflags : unknown Pentium4 model\n" ); 
			$cpu = "p4"; }
	    }
	}
        elsif ( $vendor eq "CentaurHauls" )
        {
            if ( $family eq "6" )
            {
                # VIA C3
		if ( $model eq "9" ) { $cpu = "via-c3a"; }
                else { error( "cpuflags : unknown C3 model\n" ); 
		       $cpu = "via-c3"; }
            }
        }
	else
	{
	    error( "cpuflags : unknown cpu-vendor\n" );
	    $cpu = "i386";
	}
    }
    elsif ( $cputype ne "" )
    {
	if ( $cputype eq "745/755" ) { $cpu = "ppc750"; }
	else { error( "cpuflags : unknown cpu\n" ); }
    }
    else
    {
	error( "cpuflags : unknown structure in /proc/cpuinfo\n" );
	exit 1;
    }
}

###############################################################
#
# functions for Solaris
#

sub parse_solaris
{
    $isalist = `isalist`;
    $optisa  = `optisa $isalist`;
    $optisa  =~ s/\n//g;

    print "CPU = $optisa\n" if ( $verbosity >= 1 );

    if    ( $optisa eq "sparcv9" )      { $cpu = "ultra1"; }
    elsif ( $optisa eq "sparcv9+vis" )  { $cpu = "ultra2"; }
    elsif ( $optisa eq "sparcv9+vis2" ) { $cpu = "ultra3"; }
    else  { error( "cpuflags: unsupported processor ($optisa)" ); }
}

###############################################################
#
# functions for AIX
#

sub parse_aix
{
    @cfg = `/usr/sbin/lscfg | awk 'BEGIN { FS = "[ \t]+" } { print $2 }'`;

    foreach $line (@cfg)
    {
	if ( $line =~ /.*proc.*/ )
	{
            @entry = split( /[ \t]+/, $line );
            $proc = $entry[1];
            $info = `/usr/sbin/lscfg -p -l $proc | grep -i name`;

            if ( $info =~ /.*POWER4.*/ ) { $cpu = "power4" }
            else { error( "cpuflags: unsupported processor ($info)\n" ); }
            return;
	}
    }
}

###############################################################
#
# functions for IRIX
#

sub parse_irix
{
    @cfg = `hinv`;

    foreach $line (@cfg)
    {
	if ( $line =~ /.*CPU.*/ )
	{
            @entry = split( /[ \t]+/, $line );
            $proc = $entry[2];

            if ( $proc =~ /.*R10000.*/ ) { $cpu = "r10000" }
            else { error( "cpuflags: unsupported processor ($proc)\n" ); }
            return;
	}
    }
}

###############################################################
#
# functions for Darwin (aka MacOSX)
#

sub parse_darwin
{
    #
    # determine CPU type
    #

    $cputype    = "";
    $cpusubtype = "";

    @cfg = `sysctl -a`;

    foreach $line (@cfg)
    {
	if ( $line =~ /cputype/i )
	{
	    $cputype = $line;
	    $cputype =~ s/.*\: *//g;
	    $cputype =~ s/\n//g;
	}
	elsif ( $line =~ /cpusubtype/i )
	{
	    $cpusubtype = $line;
	    $cpusubtype =~ s/.*\: *//g;
	    $cpusubtype =~ s/\n//g;
	}
    }

    print "CPU type/subtype = $cputype / $cpusubtype\n" if ( $verbosity >= 1 );

    #
    # set processor name
    #

    if ( $cputype eq "18" )
    {
	$cpu = "ppc7450"; 
    }
    else
    {
	error( "cpuflags: unsupported processor (cputype = $cputype)\n" ); 
	$cpu = "ppc"; 
    }
}

###############################################################
###############################################################
##
## determine compiler version
##
###############################################################
###############################################################

sub parse_comp_output
{
    foreach $line (@_)
    {
	print "output: $line" if ( $verbosity >= 2 );

	if ( $line =~ /^gcc.* (\d+)\.(\d+)/i )                     { $compversion = "gcc-$1.$2"; return; }
	if ( $line =~ /intel.*compiler.*version.* (\d+)\.(\d+)/i ) { $compversion = "icc-$1.$2"; return; }
	if ( $line =~ /pg(cc|CC|f77|f90) (\d+)\.(\d+)/i )          { $compversion = "pgi-$2.$3"; return; }
	if ( $line =~ /forte developer (\d+)/i )                   { $compversion = "suncc-$1"; return; }
	if ( $line =~ /sun workshop (\d+)/i )                      { $compversion = "suncc-$1"; return; }
	if ( $line =~ /hp.*ansi.*a\.(\d+)/i )                      { $compversion = "acc-$1"; return; }
	if ( $line =~ /mipspro compilers.* (\d+)\.(\d+)/i )        { $compversion = "mipscc-$1"; return; }
    }
}

sub compiler_version
{
    $compversion = "";

    if ( $system =~ /Linux|CYGWIN/ ) { @options = ( "-v", "-V", "--version" ); }
    else                             { @options = ( "-V", "-v", "--version" ); }

    foreach $opt (@options)
    {
	@output = `$compiler $opt 2>&1`;

	parse_comp_output( @output );

	if ( $compversion ne "" )
	{
	    $compsubver = $compversion;
	    $compsubver =~ s/.*\.//g;
	    return;
	}
    }

    error( "could not determine compiler version\n" );
}

###############################################################
###############################################################
##
## main program
##
###############################################################
###############################################################

parse_cmdline();

#
# determine operating system
#

$system = `uname -s`;
$system =~ s/\n//g;

# adjust name
if ( $system eq "SunOS" )  { $system = "Solaris"; }
if ( $system eq "IRIX64" ) { $system = "IRIX"; }

#
# determine compiler version
#

compiler_version() if ( $compversion eq "" );

if ( $compversion eq "" )
{
    error( "unsupported compiler\n" );
    exit( 1 );
}

print "compiler = $compversion\n" if ( $verbosity >= 1 );

#
# determine processor
#

if ( $cpu eq "" )
{
    if    ( $system =~ /Linux|CYGWIN/ ) { parse_linux();   }
    elsif ( $system eq "Solaris" )      { parse_solaris(); }
    elsif ( $system eq "AIX" )          { parse_aix(); }
    elsif ( $system eq "IRIX" )         { parse_irix(); }
    elsif ( $system eq "Darwin" )       { parse_darwin(); }
    else  { error( "cpuflags: unknown system ($system)\n" ); exit( 1 ); }
}

#
# setup cflags
#

if ( $show_cflags == 1 ) { set_cflags(); }
if ( $show_oflags == 1 ) { set_oflags(); }

#
# output everything
#

if ( $show_cpu == 1 )
{
    print "$cpu\n";
}
else
{
    # standard flags
    $oflags = $std_oflags if ( $oflags eq "" );

    # first print optimisation flags to omit warnings of sun-compiler
    print "$oflags " if ( $show_oflags == 1 );
    print "$cflags " if ( $show_cflags == 1 );
    print "\n"       if ( $show_cflags == 1 or $show_oflags == 1 );
}
